package vip.liux.front.infrastructure.jpa.point;

import jakarta.persistence.criteria.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import vip.liux.contracts.models.point.PointsTransaction;
import vip.liux.contracts.repositories.point.IPointsTransactionRepository;
import vip.liux.contracts.shared.enums.point.TransactionStatus;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;

public interface JpaPointsTransactionRepository extends IPointsTransactionRepository, JpaRepository<PointsTransaction, Long>, JpaSpecificationExecutor<PointsTransaction> {

    @Query("SELECT COALESCE(SUM(t.points), 0) FROM PointsTransaction t " +
            "WHERE t.userId = :userId " +
            "AND t.creationTime BETWEEN :start AND :end " +
            "AND t.status = vip.liux.contracts.shared.enums.point.TransactionStatus.COMPLETED")
    BigDecimal sumTodayPointsByUserAndRule(
            @Param("userId") Long userId,
            @Param("start") LocalDateTime start,
            @Param("end") LocalDateTime end);

    @Override
    default Page<PointsTransaction> findByUserId(Long userId, String transactionNo, String relatedNo, String ruleCode, LocalDate transactionDateStart, LocalDate transactionDateEnd, Pageable page) {
        return findAll((root, query, criteriaBuilder) -> {
            java.util.List<Predicate> predicates = new java.util.ArrayList<>();
            if (userId != null) {
                predicates.add(criteriaBuilder.equal(root.get("userId"), userId));
            }
            if (StringUtils.isNotBlank(transactionNo)) {
                predicates.add(criteriaBuilder.equal(root.get("transactionNo"), transactionNo));
            }
            if (StringUtils.isNotBlank(relatedNo)) {
                predicates.add(criteriaBuilder.equal(root.get("relatedNo"), relatedNo));
            }
            if (transactionDateStart != null) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("creationTime").as(LocalDate.class), transactionDateStart));
            }
            if (transactionDateEnd != null) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("creationTime").as(LocalDate.class), transactionDateEnd));
            }
            if (ruleCode != null) {
                predicates.add(criteriaBuilder.equal(root.get("ruleCode"), ruleCode));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        }, page);
    }

    @Modifying
    @Override
    @Query("UPDATE PointsTransaction t SET t.status = :newStatus WHERE t.id = :id AND t.status = :status")
    int updateStatusByIdAndStatus(TransactionStatus status, Long id, TransactionStatus newStatus);
}
